#ifndef DLIST_H
#define DLIST_H

//计算偏移地址
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER)

//计算大结构体的首地址
//第一行：设置临时变量_mptr，确保ptr与member类型一致
//第二行：强转(char*) 按字节寻址
#define container_of(ptr,type,member) ({               \
    const typeof(((type*)0)->member)* _mptr = (ptr);   \
    (type*)((char*)_mptr - offsetof(type,member));})


struct list_head
{
    struct list_head* prev;
    struct list_head* next;
};

//初始化链表头结点
#define LIST_HEAD_INIT(name) {&(name),&(name)}

//传变量
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)

//传指针，用do_while将两行代码包成一行
#define INIT_LIST_HEAD(ptr) \
do{ \
    (ptr)->next = (ptr); \
    (ptr)->prev = (ptr); \
}while(0)


//往两个节点之间插入一个新的节点
static inline void __list_add(struct list_head* pNew,
                struct list_head* prev,
                struct list_head* next)
{
    next->prev = pNew;
    pNew->next = next;      //先连接尾结点

    pNew->prev = prev;
    prev->next = pNew;      //再连接头节点， 貌似顺序不能随便修改，不然在多进程时会出现一些问题导致链表断裂
}

//头插
static inline void list_add(struct list_head* pNew, struct list_head* head)
{
    __list_add(pNew, head, head->next);
}

//尾插， 循环双链表，所以能直接用head->prev访问尾节点 
static inline void list_add_tail(struct list_head* pNew, struct list_head* head)
{
    __list_add(pNew, head->prev, head);
}

//删除节点，给定一个节点的prev指针和next指针，删除该节点
static inline void __list_del(struct list_head* prev, struct list_head* next)
{
    next->prev = prev;
    prev->next = next;
}

//删除节点
static inline void list_del(struct list_head* entry)
{
    __list_del(entry->prev, entry->next);

    //指针指空，避免使用野指针
    entry->prev = (void*)0;
    entry->next = (void*)0;
}
//删除该节点并且重新初始化该节点
static inline void list_del_init(struct list_head* entry)
{
    __list_del(entry->prev, entry->next);
    INIT_LIST_HEAD(entry);
}

//删除该节点并且把该节点插入到另一个链表的头部
static inline void list_move(struct list_head* list, struct list_head* head)
{
    __list_del(list->prev, list->next);
    list_add(list,head);
}

//删除该节点并且把该节点插入到另一个链表的尾部
static inline void list_move_tail(struct list_head* list, struct list_head* head)
{
    __list_del(list->prev, list->next);
    list_add_tail(list,head);
}

//判断链表是否为空
static inline int list_empty(struct list_head* head)
{
    return head->next == head;
}


//合并两个链表      有点像头插
static inline void __list_splice(struct list_head* list, struct list_head* head)
{
    struct list_head* first = list->next;   //首
    struct list_head* last =  list->prev;   //尾
    struct list_head* at = head->next;      //头节点的下一个位置

    //首和头结点相连
    first->prev = head;
    head->next = first;

    //尾和头结点下一个位置想连
    last->next = at;
    at->prev = last;
    
}

//合并两个链表
static inline void list_splice(struct list_head* list, struct list_head* head)
{
    //判断list链表是否为空
    if (!list_empty(list)) 
        __list_splice(list, head);
}



//合并两个链表，并重新初始化已清空的链表
static inline void list_splice_init(struct list_head* list, struct list_head* head)
{
    if (!list_empty(list)) {
        __list_splice(list,head);
        INIT_LIST_HEAD(list);
    }
}


//求出大结构体首地址
#define list_entry(ptr, type , member) \
((type*)((char*)(ptr) - (unsigned long)(&((type*)0)->member)))



//下面遍历链表方式有点像迭代器，或者说就是迭代器的遍历方式

//循环向后遍历链表函数
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); \
pos = pos->next)


//循环向前遍历链表函数
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; pos != (head); \
pos = pos->prev)

#define list_for_each_prev_safe(pos,n,head)\
for (pos = (head)->prev,n = pos->prev; pos != (head);\
pos = n, n = pos->prev)

//安全遍历链表并且允许删除当前节点
//关键点在于提前存储了下一个节点的地址
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)


//遍历大结构体
#define list_for_each_entry(pos, head, member)  \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos),member))


//安全遍历大结构体并且允许删除当前节点
//关键带你在于提前存储了下一个节点的地址
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(pos->member.next, typeof(*pos), member))


//list_entry 和 container_of 的 区别
//list_entry仅适用于内核链表
//container_of是一个“成员转结构体”的通用工具，
//list_entry可以依赖于container_of


#endif //DLIST_H

